class_name HoldMeleeWeapon
extends BaseHoldItem

@onready var sprite_idle: Sprite2D = $SpriteIdle
@onready var sprite_attack: Sprite2D = $SpriteAttack

# hit
@onready var hit_area: Area2D = $HitArea
@onready var hit_collision: CollisionPolygon2D = $HitArea/CollisionPolygon2D
var hit_targets: Array = []
var hit_drop_items: Array = []

var drains_holder_health_timer: float = 1.0


func _ready() -> void:
	stop_attack()


func attack():
	sprite_idle.visible = false
	sprite_attack.visible = true
	hit_collision.disabled = false
	hit_collision.visible = true
	
	hit_targets = []
	hit_drop_items = []
	
	var config = item_data.item_config as MeleeWeaponConfig
	if config.attack_cam_shake:
		var player = holder as Player
		player.level.camera.start_shake(config.attack_cam_shake_intensity, config.attack_cam_shake_duration)
	
	AudioManager.play_sound("sfx_sword_swing")
	

func stop_attack():
	sprite_idle.visible = true
	sprite_attack.visible = false
	hit_collision.disabled = true
	hit_collision.visible = false


func _physics_process(delta: float) -> void:
	process_hit()
	process_hit_drop_item()
	process_drains_holder_health(delta)
	

func process_drains_holder_health(delta: float):
	var config = item_data.item_config as MeleeWeaponConfig
	if not config.drains_holder_health_damage_per_second: return
		
	drains_holder_health_timer -= delta
	if drains_holder_health_timer <= 0:
		drains_holder_health_timer = 1.0
		
		var player = holder as Player
		
		var hit_data = HitData.new()
		hit_data.is_critical = true
		hit_data.is_direct_damage = true
		hit_data.direct_damage = ceil(player.unit_data.max_hp * config.drains_holder_health_damage_per_second) 
		hit_data.knockback = 0
		
		player.take_hit(hit_data)
	

func process_hit():
	if hit_collision.disabled: return
	
	var areas = hit_area.get_overlapping_areas()
	if areas.size() <= 0: return
	
	for area in areas:
		var source = area.source
		if source not in hit_targets:
			hit_targets.append(source)
			source.take_hit(get_hit_data(), holder)
			
			if source is UnitBase:
				add_debuff_to_unit(source)
				

func add_debuff_to_unit(source: Node2D):
	var config = item_data.item_config as MeleeWeaponConfig
	if config.flame_debuff_hit_rate:
		add_debuff_flame_to_unit(source)
	if config.blood_hit_rate:
		add_blood_effect(source)
	if config.poison_hit_rate:
		add_poison_effect(source)
	if GlobalData.find_item_by_name("麻痹戒指"):
		add_numb_effect(source)
		

func add_poison_effect(source: Node2D):
	var config = item_data.item_config as MeleeWeaponConfig
	var unit = source as UnitBase
	
	var hit_rate = config.poison_hit_rate
	var is_hit = randf() < hit_rate
	if is_hit and not unit.get_buff_by_name("buff_poison"):
		var buff_inst = unit.add_buff("buff_poison", holder)
		
		buff_inst.duration = config.poison_debuff_duration
		buff_inst.damage_per_second = config.poison_damage_per_second
		buff_inst.start_buff()		

	
func add_numb_effect(source: Node2D):
	var item_data = GlobalData.find_item_by_name("麻痹戒指")
	
	var numb_hit_rate =  item_data.item_config.numb_hit_rate
	var is_hit = randf() < numb_hit_rate
	if is_hit and not source.get_buff_by_name("debuff_numb"):
		var buff_inst = source.add_buff("debuff_numb", holder)
		
		buff_inst.numb_speed_scale = item_data.item_config.numb_speed_scale
		buff_inst.duration = item_data.item_config.numb_duration
		buff_inst.start_buff()
	

func add_debuff_flame_to_unit(source: Node2D):
	var config = item_data.item_config as MeleeWeaponConfig
	var unit = source as UnitBase
	
	var hit_rate = config.flame_debuff_hit_rate
	var is_hit = randf() < hit_rate
	if is_hit and not unit.get_buff_by_name("debuff_flame"):
		var buff_inst = unit.add_buff("debuff_flame", holder)
		
		buff_inst.duration = config.flame_debuff_duration
		buff_inst.damage_per_second = config.flame_damage_per_second
		buff_inst.sender = holder
		buff_inst.start_buff()
		

func add_blood_effect(source: Node2D):
	var config = item_data.item_config as ItemBaseConfig
	var unit = source as UnitBase
	var player = holder as Player
	
	var hit_rate = config.blood_hit_rate
	var is_hit = randf() < hit_rate		
	if is_hit:
		var hit_data = HitData.new()
		hit_data.is_critical = true
		hit_data.is_direct_damage = true
		hit_data.direct_damage = unit.unit_data.max_hp * config.blood_hit_damage_percent
		hit_data.knockback = config.knockback
		
		unit.take_hit(hit_data)
		player.level.emit_particle("particle_blood_hit_effect", unit.get_random_hurt_position())
		

func get_hit_data():
	var player: Player = holder as Player
	var config: MeleeWeaponConfig = item_data.item_config as MeleeWeaponConfig
	
	var critical_rate = config.critical_rate
	var is_critical = (randf() <= critical_rate)
	var attack = (player.player_data.get_attack() + config.attack) * (1.0 + player.get_attack_charge_rate())
	var critical_attack = attack * (1.0 + config.critical_bonus) 
	
	var hit_data = HitData.new()
	hit_data.is_critical = is_critical
	hit_data.attack = attack if not is_critical else critical_attack
	hit_data.knockback = config.knockback
	
	return hit_data
			

func process_hit_drop_item():
	if hit_collision.disabled: return
	
	var bodies = hit_area.get_overlapping_bodies()
	if bodies.size() <= 0: return
	
	var player: Player = holder as Player
	
	for body in bodies:
		if body is RigidBody2D :
			var target = body as RigidBody2D
			if target.can_push and target not in hit_drop_items:
				hit_drop_items.append(target)
				target.apply_impulse(Vector2.RIGHT * player.get_face() * player.player_data.get_push_item_power())
			
			
